package com.neulogistics.contrib.transfercenter.api.application.integrationevent.handler;

import com.blackto.lib.eventbus.abstraction.IIntegrationEventHandler;
import com.neulogistics.contrib.transfercenter.api.application.integrationevent.ITransferCenterIntegrationEventService;
import com.neulogistics.contrib.transfercenter.api.application.integrationevent.publish.TransferOrderCreatedIntegrationEvent;
import com.neulogistics.contrib.transfercenter.api.application.integrationevent.subscribe.OrderExchangedIntegrationEvent;
import com.neulogistics.contrib.transfercenter.api.application.integrationevent.subscribe.OrderReturnedIntegrationEvent;
import com.neulogistics.contrib.transfercenter.api.application.rpc.ITransferCenterRPC;
import com.neulogistics.contrib.transfercenter.api.service.ThreadLocalService;
import com.neulogistics.contrib.transfercenter.domain.model.aggregate.TransferOrder;
import com.neulogistics.contrib.transfercenter.domain.model.enumeration.TransferType;
import com.neulogistics.contrib.transfercenter.domain.model.valueobject.OrderItem;
import com.neulogistics.contrib.transfercenter.domain.repository.ITransferOrderRepository;
import com.neulogistics.infrastructure.cache.idservice.RedisIdUtil;
import com.neulogistics.infrastructure.common.annotation.ProduceEvent;
import com.neulogistics.infrastructure.integrationeventlog.model.IntegrationEventConstant;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.TransactionStatus;
import org.springframework.transaction.support.TransactionCallbackWithoutResult;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletableFuture;

@Slf4j
@Component
public class OrderExchangedIntegrationEventHandler implements IIntegrationEventHandler<OrderExchangedIntegrationEvent> {

    @Resource
    ITransferCenterRPC transferCenterRPC;

    @Resource
    ITransferOrderRepository transferOrderRepository;

    @Resource
    ITransferCenterIntegrationEventService transferCenterIntegrationEventService;

    @Resource
    private TransactionTemplate transactionTemplate;

    @Resource
    RedisIdUtil redisIdUtil;

    @Value("${spring.application.name}")
    private String appName;

    private final String Transfer_Order_Id_Key;

    public OrderExchangedIntegrationEventHandler(@Value("${spring.application.name}") String appName) {
        Transfer_Order_Id_Key = appName + ":" + "transferOrderId";
    }

    @Override
    @ProduceEvent
    public CompletableFuture<Void> handle(OrderExchangedIntegrationEvent event) {
        // 依据收货地址，调用地理计算服务，获取推荐的中心库房和分站库房
        Map<String, Integer> recommendedWarehouse = transferCenterRPC.getRecommendedWarehouse(event.receiverAddress);
        Integer centerId = recommendedWarehouse.get("center");
        Integer substationId = recommendedWarehouse.get("substation");

        // 生成调度单
        Long transferOrderId = redisIdUtil.nextId(Transfer_Order_Id_Key);
        Long orderId = event.orderId;
        List<OrderItem> orderItems = event.orderItems;
        Date expDeliveryTime = event.expDeliveryTime;

        TransferOrder transferOrder = new TransferOrder(transferOrderId, TransferType.Exchange,
                orderId, centerId, substationId, orderItems, expDeliveryTime);

        // 开启事务
        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
            @Override
            protected void doInTransactionWithoutResult(TransactionStatus status) {
                try {
                    // 调用仓储，调度单持久化
                    transferOrderRepository.save(transferOrder);

                    // 生成集成事件id并创建调度单生成事件
                    Long eventId = redisIdUtil.nextId(IntegrationEventConstant.Integration_Event_Id_Key);
                    TransferOrderCreatedIntegrationEvent transferOrderCreatedIntegrationEvent
                            = new TransferOrderCreatedIntegrationEvent(eventId);
                    transferOrderCreatedIntegrationEvent.setOrderId(transferOrder.getOrderId());
                    transferOrderCreatedIntegrationEvent.setTransferOrderId(transferOrder.getTransferOrderId());

                    // 获取当前事务id，并保存该集成事件
                    Long transactionId = ThreadLocalService.transactionId.get();
                    transferCenterIntegrationEventService.addAndSaveEvent(transferOrderCreatedIntegrationEvent, transactionId);
                } catch (Exception e){
                    // 触发回滚
                    throw new RuntimeException(e.getCause().getMessage());
                }
            }
        });

        return CompletableFuture.completedFuture(null);
    }
}
